﻿using System;
using System.Collections.Generic;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using ShevaEngine.Core.Interfaces;
using ShevaEngine2GUI.Foundation;
using ShevaEngine.Core.Modules.Materials;
using ShevaEngine.Core.Foundation;
using ShevaEngine.Core.Modules;
using ShevaEngine2GUI.Bindings;

namespace ShevaEngine2GUI
{
    /// <summary>
    /// Control.
    /// </summary> 
    public class Control : IUpdateAble
    {
        /// <summary>Anchor.</summary>
        public AnchorStyles Anchor;
        /// <summary>Back color.</summary>
        public Color BackColor;
        /// <summary>Background image.</summary>
        public Texture2D BackgroundImage;
        /// <summary>Background image layout.</summary>
        public ImageLayout BackgroundImageLayout;
        /// <summary>Controls.</summary>
        public NotificationList<Control> Controls;
        /// <summary>Data binding.</summary>
        public IBinding DataBinding;
        /// <summary>Dock.</summary>
        public DockStyle Dock;
        /// <summary>Enabled.</summary>
        public Boolean Enabled;
        /// <summary>Font.</summary>
        public SpriteFont Font;
        /// <summary>Forecolor.</summary>
        public Color ForeColor;
        /// <summary>Location and size.</summary>
        public Rectangle LocationSize;
        /// <summary>Real location size</summary>
        internal Rectangle RealLocationSize;
        /// <summary>Name.</summary>
        public string Name;
        /// <summary>Parent.</summary>
        public Control Parent;
        /// <summary>Tab index.</summary>
        public Int32 TabIndex;
        /// <summary>Text.</summary>
        private string _Text;
        /// <summary>Text.</summary>
        public string Text
        {
            get
            {
                if (this.DataBinding != null)
                    return this.DataBinding.GetValue().ToString();
                else
                    return this._Text;
            }
            set { this._Text = value; }
        }
        /// <summary>Visible.</summary>
        public Boolean Visible;

        /// <summary>Tag.</summary>
        public object Tag;
        /// <summary>Child processed.</summary>
        private bool ChildProcessed;
        /// <summary>Under cursor.</summary>
        internal bool ControlUnderCursor;

        /// <summary>Cursor enter.</summary>
        public event EventHandler CursorEnter;
        /// <summary>Cursor leave.</summary>
        public event EventHandler CursorLeave;

        /// <summary>
        /// Constructor.
        /// </summary>
        public Control()
        {
            this.Anchor = AnchorStyles.Top | AnchorStyles.Left;
            this.BackColor = Color.Transparent;
            this.BackgroundImage = null;
            this.BackgroundImageLayout = ImageLayout.None;
            this.Controls = new NotificationList<Control>();
            this.Controls.ItemAdded += new NotificationList<Control>.OnNotificationListChangedCallback(this.ControlsChanged);
            this.Controls.ItemRemoved += new NotificationList<Control>.OnNotificationListChangedCallback(this.ControlsChanged);
            this.Dock = DockStyle.None;
            this.Enabled = true;
            this.Font = FontManager.Instance["Arial12"];
            this.ForeColor = Color.Black;            
            this.Visible = true;
            

            this.Tag = null;
        }

        /// <summary>
        /// Controls changed.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void ControlsChanged(object sender, Control e)
        {
            e.Parent = this;

            this.Redesign();
        }

        /// <summary>
        /// Method redesign control.
        /// </summary>
        public virtual void Redesign()
        {
            switch (this.Dock)
            {
                case DockStyle.None:
                    if (this.Parent != null)
                        this.RealLocationSize = new Rectangle(this.LocationSize.X + this.Parent.RealLocationSize.X, this.LocationSize.Y + this.Parent.RealLocationSize.Y,
                            this.LocationSize.Width, this.LocationSize.Height);
                    else
                        this.RealLocationSize = this.LocationSize;
                    break;
                case DockStyle.Top:
                    this.RealLocationSize = new Rectangle(this.Parent.RealLocationSize.X, this.Parent.RealLocationSize.Y, 
                        this.Parent.RealLocationSize.Width, this.LocationSize.Height);
                    break;
                case DockStyle.Bottom:
                    this.RealLocationSize = new Rectangle(this.Parent.RealLocationSize.X, this.Parent.RealLocationSize.Y + this.Parent.RealLocationSize.Height - this.LocationSize.Height,
                        this.Parent.RealLocationSize.Width, this.LocationSize.Height);
                    break;
                case DockStyle.Left:
                    this.RealLocationSize = new Rectangle(this.Parent.RealLocationSize.X, this.Parent.RealLocationSize.Y,
                        this.LocationSize.Width, this.Parent.RealLocationSize.Height);
                    break;
                case DockStyle.Right:
                    this.RealLocationSize = new Rectangle(this.Parent.RealLocationSize.X + this.Parent.RealLocationSize.Width - this.LocationSize.Width, this.Parent.RealLocationSize.Y,
                        this.LocationSize.Width, this.Parent.RealLocationSize.Height);
                    break;
                case DockStyle.Fill:
                    this.RealLocationSize = this.Parent.RealLocationSize;
                    break;                
            }

            foreach (Control control in this.Controls)
                control.Redesign();
        }

        /// <summary>
        /// Method Update().
        /// </summary>
        /// <param name="time"></param>
        public virtual void Update(GameTime time)
        {
            foreach (Control control in this.Controls)
                control.Update(time);
        }

        /// <summary>
        /// Method Draw().
        /// </summary>
        public virtual void Draw()
        {
            if (this.BackColor != Color.Transparent)
                ShevaEngine.Core.ShevaEngine.Instance.SpriteBatch.Draw(TextureManager.Instance.WhiteTexture, this.RealLocationSize, this.BackColor);

            foreach (Control control in this.Controls)
                control.Draw();
        }

        /// <summary>
        /// Mouse move.
        /// </summary>
        /// <param name="position"></param>
        public virtual bool MouseMove(Vector2 position)
        {
            if (this.RealLocationSize.X <= position.X && this.RealLocationSize.X + this.RealLocationSize.Width >= position.X &&
                this.RealLocationSize.Y <= position.Y && this.RealLocationSize.Y + this.RealLocationSize.Height >= position.Y)
            {
                this.ChildProcessed = false;

                foreach (Control control in this.Controls)
                    this.ChildProcessed = this.ChildProcessed || control.MouseMove(position);

                if (this.ChildProcessed)
                {
                    if (this.ControlUnderCursor && this.CursorLeave != null)
                        this.CursorLeave(this, null);

                    this.ControlUnderCursor = false;
                }
                else
                {
                    if (!this.ControlUnderCursor && this.CursorEnter != null)
                        this.CursorEnter(this, null);

                    this.ControlUnderCursor = true;
                }

                return true;
            }
            else
            {
                if (this.ControlUnderCursor && this.CursorLeave != null)
                    this.CursorLeave(this, null);

                this.ControlUnderCursor = false;
            }
            
            return false;
        }

        
    }    
}
